#include "Hash.h"
#include "unixHeader.h"

// 引入 OpenSSL 库提供的 SHA-1 实现所需的头文件
#include <openssl/sha.h> 
#include <iostream>
using std::cout;
using std::endl;
using std::string;

// 自定义 Hash 类的 const 成员函数，用于计算文件的 SHA-1 散列值
std::string Hash::sha1() const
{
    // 将 string 类型的文件名转换成 C 风格的字符串
    int fd = open(_filename.c_str(), O_RDONLY);
    cout << "_filename:" << _filename << endl;
    if (fd < 0)
    {
        perror("open");
        return string();
    }
    char buff[1024] = {0};
    // 定义了一个结构体变量 ctx，用于存储 SHA-1 计算的上下文信息
    SHA_CTX ctx;
    // 初始化 SHA-1 计算上下文
    SHA1_Init(&ctx);

    // 不断地从文件中读取数据并更新 SHA-1 计算上下文，直到文件被完全读取
    while (1)
    {
        int ret = read(fd, buff, 1024);
        if (ret == 0)
        { // 如果从文件中读取的字节数为零，即到达文件末尾，那么退出循环
            break;
        }
        // 更新 SHA-1 计算上下文，将 buff 中的数据纳入到计算范围内
        // 这样做是为了对文件内容进行 SHA-1 散列计算
        SHA1_Update(&ctx, buff, ret);
        bzero(buff, sizeof(buff));
    }
    unsigned char md[20] = {0};
    // 完成 SHA-1 散列计算，将最终结果存储在 md 数组中
    SHA1_Final(md, &ctx);
    // 用于存储 SHA-1 散列值的每个字节的十六进制表示
    char fragment[3] = {0};
    string result;
    // 将计算得到的二进制散列值转换为十六进制字符串
    for (int i = 0; i < 20; ++i)
    {
        // 使用 sprintf 函数将 md[i] 中的一个字节转换为十六进制字符串，并存储在 fragment 中
        sprintf(fragment, "%02x", md[i]);
        result += fragment;
    }
    // 返回文件的 SHA-1 散列值的十六进制表示
    return result;
}
